package tools.chapter18;

import java.util.concurrent.locks.StampedLock;

/**
 * @author Kevin
 * @date 2020/4/8 20:48
 */
public class Point {
    private double x, y;
    final StampedLock sl = new StampedLock();
    //计算到原点的距离
    public double distanceFromOrign() {
        //乐观读
        long stamp = sl.tryOptimisticRead();
        //读入局部变量
        //读入的数据可能被修改
        double curX = x, curY = y;
        //判断执行读操作期间，
        //是否存在写操作，如果存在
        //则sl.validate返回false
        if (!sl.validate(stamp)) {
            //升级悲观读锁
            stamp = sl.readLock();
            try {
                curX = x;
                curY = y;
            } finally {
                //释放悲观读锁
                sl.unlockRead(stamp);
            }
        }
        return  Math.sqrt(
                curX * curX + curY * curY
        );
    }

    // StampedLock 支持锁的降级（通过 tryConvertToReadLock() 方法实现）和升级（通过 tryConvertToWriteLock() 方法实现）
    // 存在问题的方法，修改后隐藏了个BUG
    public void moveIfAtOrigin(double newX, double newY) {
        long stamp = sl.readLock();
        try {
            while (x == 0.0 && y == 0.0) {
                long ws = sl.tryConvertToWriteLock(stamp);
                if (ws != 0L) {
                    x = newX;
                    y = newY;
                    break;
                } else {
                    sl.unlockRead(stamp);
                    //在锁升级成功的时候，最后没有释放最新的写锁，可以在if块的break上加个stamp=ws进行释放
                    stamp = sl.writeLock();
                }
            }
        } finally {
            sl.unlock(stamp);
        }
    }
}
